#pragma once

#include <iostream>
#include <queue>
#include <pthread.h>

using namespace std;

static int gcap=8;
template<class T>
class BlockQueue
{
public:
    BlockQueue(const int cap = gcap):_cap(cap)
    {
        pthread_mutex_init(&_mutex, nullptr);
        pthread_cond_init(&_consumerCond, nullptr);
        pthread_cond_init(&_productorCond, nullptr);
    }
    bool isEmpty(){
       if(_q.empty()){
        return true;
       }
    }
    bool isFull(){
        if(_q.size()==_cap){
            return true;
        }
    }
    void push(const T &in)
    {
    pthread_mutex_lock(&_mutex);
    //阻塞队列满了，不满足生产者条件，放入生产者条件变量的等待队列中去。
    while(isFull()){
        pthread_cond_wait(&_productorCond,&_mutex);
    }
    //没有满的，就让它生产
    _q.push(in); //生产数据到阻塞队列中
    //通知消费者消费
    // 加策略
    if(_q.size() >= _cap/2){
    pthread_cond_signal(&_consumerCond); //唤醒消费者队列中的线程
    }
    pthread_mutex_unlock(&_mutex); //归还锁
    }
    ~BlockQueue()
    {
        pthread_mutex_destroy(&_mutex);
        pthread_cond_destroy(&_consumerCond);
        pthread_cond_destroy(&_productorCond);
    }
    //消费者消费数据
    void pop(T *out)
    {
        pthread_mutex_lock(&_mutex);
        //阻塞队列为空，不满足消费数据条件，放入消费者条件变量的等待队列中
        while(isEmpty()) 
        {
            pthread_cond_wait(&_consumerCond, &_mutex);
        }
        //队列中有数据，进行消费
        *out = _q.front();
        _q.pop();
        // 通知生产者继续生产
        if(_p.size()<cap/2){
        pthread_cond_signal(&_productorCond);
        }
        pthread_mutex_unlock(&_mutex);
    }
private:
    queue<T> _q;
    int _cap;
    // 为什么我们的这份代码，只用一把锁呢，根本原因在于，
    // 我们生产和消费访问的是同一个queue&&queue被当做整体使用！
    pthread_mutex_t _mutex; 
    pthread_cond_t _consumerCond;   // 消费者对应的条件变量，空，wait
    pthread_cond_t _productorCond;  // 生产者对应的条件变量，满，wait
};

//增加保存线程
template <class c, class s>
class BlockQueues
{
public:
    BlockQueue<c>* c_bq;//计算任务阻塞队列
    BlockQueue<s>* s_bq;//保存任务阻塞队列
};